﻿#region Usings

using System;
using System.Windows;
using System.Windows.Media;

#endregion

namespace SilverBox.Physics
{
    public static class MathEx
    {
        public static double InterpolateQuad(double percent, double min, double max)
        {
            return Interpolate(percent, min, max, 0, 1);
        }

        public static double Interpolate(double percent, double min, double max, double easeIn, double easeOut)
        {
            double a = WeightedAverage(0, easeIn, percent);
            double b = WeightedAverage(easeIn, easeOut, percent);
            double c = WeightedAverage(easeOut, 1, percent);
            double aa = WeightedAverage(a, b, percent);
            double bb = WeightedAverage(b, c, percent);

            return WeightedAverage(aa, bb, percent)*(max - min) + min;
        }

        private static double WeightedAverage(double a, double b, double t)
        {
            return (1 - t)*a + t*b;
        }

        public static double Log(double a, double newBase)
        {
            return Math.Log(a)/Math.Log(newBase);
        }

        public static double Clamp(double value, double min, double max)
        {
            return Math.Min(Math.Max(value, min), max);
        }

        public static int Clamp(int value, int min, int max)
        {
            return Math.Min(Math.Max(value, min), max);
        }

        public static double Rad2Deg(double r)
        {
            return r*180.0/Math.PI;
        }

        public static double Deg2Rad(double d)
        {
            return d*Math.PI/180.0;
        }

        public static Vector Sub(this Point a, Point b)
        {
            return new Vector(a.X - b.X, a.Y - b.Y);
        }

        public static Vector Sub(this Point a, Vector b)
        {
            return new Vector(a.X - b.X, a.Y - b.Y);
        }

        public static Vector Add(this Point a, Point b)
        {
            return new Vector(a.X + b.X, a.Y + b.Y);
        }

        public static Vector Add(this Point a, Size b)
        {
            return new Vector(a.X + b.Width, a.Y + b.Height);
        }

        public static Vector Div(this Point a, double dividend)
        {
            return new Vector(a.X/dividend, a.Y/dividend);
        }

        public static Vector Mul(this Point a, double scalar)
        {
            return new Vector(a.X*scalar, a.Y*scalar);
        }

        public static Size Mul(this Size a, double scalar)
        {
            return new Size(a.Width*scalar, a.Height*scalar);
        }

        public static Size Div(this Size a, double scalar)
        {
            return new Size(a.Width/scalar, a.Height/scalar);
        }


        public static void Offset(this Rect rect, double offsetX, double offsetY)
        {
            rect.X += offsetX;
            rect.Y += offsetY;
        }

        public static bool Contains(this Rect rect, double x, double y)
        {
            if (((x >= rect.X) && ((x - rect.Width) <= rect.X)) && (y >= rect.Y))
            {
                return ((y - rect.Height) <= rect.Y);
            }
            return false;
        }


        public static Matrix Invert(this Matrix value)
        {
            double inverseDeterminant = 1.0/((value.M11*value.M22) - (value.M12*value.M21));

            return new Matrix(value.M22*inverseDeterminant, -value.M12*inverseDeterminant, -value.M21*inverseDeterminant,
                              value.M11*inverseDeterminant,
                              ((value.M21*value.OffsetY) - (value.OffsetX*value.M22))*inverseDeterminant,
                              ((value.OffsetX*value.M12) - (value.M11*value.OffsetY))*inverseDeterminant);
        }
    }
}